﻿using MiniFox.Caching;
using MiniFox.Components;
using MiniFox.Platform.Configurations;
using MiniFox.Platform.Models;
using MiniFox.Utility;
using System.Drawing;
using System.Drawing.Imaging;

namespace MiniFox.Platform.Services
{
    /// <summary>
    /// 
    /// </summary>
    public class ValidationService : Component, IValidationService
    {
        const string CACHE_KEY = "ValidContext";
        ///// <summary>
        ///// 
        ///// </summary>
        //[AutoWired]
        //protected IValidationProvider Provider
        //{
        //    get;
        //    set;
        //}
        /// <summary>
        /// 
        /// </summary>
        [AutoConfigure]
        protected PinCodeConfiguration ValidCodeConfig
        {
            get;
            set;
        }
        /// <summary>
        /// 为指定验证码生成图片
        /// </summary>
        /// <param name="code"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        protected virtual byte[] GenerateImage(string code, int? width, int? height)
        {

            Image image = null;
            Graphics graphics = null;
            StringFormat format = null;
            Font font = null;
            Brush brush = null;
            Brush brush2 = null;
            int w = width ?? 80;
            int h = height ?? 30;
            try
            {
                image = new Bitmap(w, h, PixelFormat.Format32bppArgb);
                graphics = Graphics.FromImage(image);
                brush2 = Brushes.WhiteSmoke;
                graphics.FillRectangle(brush2, 0, 0, w, h);
                format = new StringFormat(StringFormatFlags.NoWrap);
                format.Alignment = StringAlignment.Center;
                format.LineAlignment = StringAlignment.Center;
                FontStyle regular = FontStyle.Bold;
                font = new Font("宋体", 16, regular);
                brush = new SolidBrush(Color.Blue);
                graphics.DrawString(code, font, brush, new RectangleF(0f, 0f, w, h), format);
            }
            catch
            {
            }
            finally
            {
                if (brush2 != null)
                {
                    brush2.Dispose();
                }
                if (brush != null)
                {
                    brush.Dispose();
                }
                if (format != null)
                {
                    format.Dispose();
                }
                if (font != null)
                {
                    font.Dispose();
                }
                if (graphics != null)
                {
                    graphics.Dispose();
                }
            }
            using (MemoryStream stream = new MemoryStream())
            {
                image.Save(stream, ImageFormat.Jpeg);

                return stream.ToArray();
            }
        }


        #region 存取验证码

        /// <summary>
        /// 设置指定验证组下的验证码，默认保存在cache中，可重写此方法，以便自定义保存模式, 注意：如果自定义保存模式，请重写CreateValidContext和GetValidContext方法，以通过同样的保存模式来读取
        /// </summary>
        /// <param name="ticket">验证票据</param>
        /// <param name="length">码文长度</param>
        protected virtual ValidationContext CreateValidContext(string ticket, int? length)
        {
            int len = length ?? 4;
            string code = Tools.GenerateRandomCode(len < 4 ? 4 : len);
            var context = new ValidationContext { Ticket = ticket, Code = code, Success = false };
            CacheService.AddCacheObject($"{CACHE_KEY}-{ticket}", context);
            return context;
        }
        /// <summary>
        /// 获取指定验证组下的验证上下文对象
        /// </summary>
        /// <param name="ticket">上下文</param>
        /// <returns></returns>
        public virtual ValidationContext GetValidContext(string ticket)
        {
            var context = CacheService.GetCacheObject<ValidationContext>($"{CACHE_KEY}-{ticket}");
            return context;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ticket"></param>
        protected virtual void ReleaseValidContext(string ticket)
        {
            CacheService.RemoveObject($"{CACHE_KEY}-{ticket}");
        }
        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ticket"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public virtual byte[] CreateRandomCodeImage(string ticket, int? width, int? height)
        {
            int len = 4;
            if (ValidCodeConfig != null)
            {
                len = ValidCodeConfig.CodeLen;
            }

            var context = CreateValidContext(ticket, len);
            var imgData = GenerateImage(context.Code, width, height);

            return imgData;

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ticket"></param>
        /// <param name="code"></param>
        /// <param name="sync"></param>
        /// <returns></returns>
        public virtual bool MatchCode(string ticket, string code, bool sync)
        {
            var context = GetValidContext(ticket);
            bool ignoreCase = false;
            if (ValidCodeConfig != null)
            {
                ignoreCase = ValidCodeConfig.IgnoreCase;
            }
            context.Success = string.Equals(code, context.Code, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
            if (sync)
                ReleaseValidContext(ticket);
            return context.Success;
        }
        /// <summary>
        /// 一次检查，无论是否通过验证，都销毁上下文对象
        /// </summary>
        /// <param name="ticket"></param>
        /// <returns></returns>
        public bool CheckResult(string ticket)
        {
            try
            {
                var context = GetValidContext(ticket);
                return context.Success;
            }
            finally
            {
                ReleaseValidContext(ticket);
            }
        }


    }
}
